package com.czy.blog.service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import com.czy.blog.dao.RoleDao;
import com.czy.blog.entity.Function;
import com.czy.blog.entity.Menu;
import com.czy.blog.entity.Role;
import com.czy.blog.utils.JsonMapper;
import com.czy.blog.vo.FunctionVo;
import com.czy.blog.vo.MenuVo;
import com.czy.blog.vo.PageVo;

@Service
@Transactional
public class RoleService
{
	@Autowired
	private RoleDao roleDao;
	@Autowired
	private MenuService menuService;
	@Autowired
	private FunctionService funcService;

	public RoleDao getRoleDao()
	{
		return roleDao;
	}

	public void setRoleDao(RoleDao roleDao)
	{
		this.roleDao = roleDao;
	}

	public void delete(List<String> ids)
	{
		Iterable<Role> roles = roleDao.findAll(ids);
		roleDao.delete(roles);
	}

	public void update(Role role)
	{
		roleDao.save(role);
	}

	public void save(Role role)
	{
		roleDao.save(role);
	}

	public Role findById(String id)
	{
		return roleDao.findOne(id);
	}

	public Page<Role> findByRoleName(String roleName, PageVo pageVo)
	{
		int pageNo = pageVo.getPage() - 1;
		Pageable page = new PageRequest(pageNo < 0 ? 0 : pageNo,pageVo.getRows());
		Page<Role> pageContent =  roleDao.findAll(findByNameSpec(roleName),page);
		return pageContent;
	}

	private Specification<Role> findByNameSpec(final String roleName)
	{
		return new Specification<Role>()
		{
			@Override
			public Predicate toPredicate(Root<Role> root, CriteriaQuery<?> query, CriteriaBuilder cb)
			{

				List<Predicate> ps = new ArrayList<Predicate>();

				if (StringUtils.isNotBlank(roleName))
				{
					ps.add(cb.like(root.<String> get("roleName"), "%" + roleName + "%"));
				}
				return cb.and(ps.toArray(new Predicate[0]));
			}
		};
	}
	
	public List<Role> findRolesByUserId(String userId)
	{
		return roleDao.findByUsersRoles_Id(userId);
	}

	public List<Role> findAll()
	{
		return (List<Role>) roleDao.findAll();
	}

	public String generalFuncJson(String roleId)
	{
		return new JsonMapper().toJson(getMenusFunctions(roleId));
	}
	
	public List<MenuVo> getMenusFunctions(String roleId){
		Role role = findById(roleId);
		Set<Menu> ownMenus = role.getMenus();
		Set<Function> ownFuncs = role.getFuncs();
		
		List<Function> funcs = funcService.findAll();
		Set<String> menuIds = new HashSet<String>();
		for(Function func : funcs){
			menuIds.add(func.getMenu().getId());
		}
		
		List<Menu> menus = menuService.findByIds(new ArrayList<String>(menuIds));
		List<MenuVo> mvos = new ArrayList<MenuVo>();
		
		for(Menu menu : menus){
			Set<FunctionVo> fvs = new HashSet<FunctionVo>();
			MenuVo mvo = new MenuVo();
			mvo.setId(menu.getId());
			mvo.setMenuname(menu.getMenuname());
			
			if(ownMenus.contains(menu)){
				mvo.setSelected(true);
			}
			for(Function func : funcs){
				if(menu.getId().equals(func.getMenu().getId())){
					FunctionVo fvo = new FunctionVo();
					fvo.setId(func.getId());
					fvo.setMenuId(mvo.getId());
					fvo.setFuncCode(func.getFuncCode());
					fvo.setFuncName(func.getFuncName());
					
					if(ownFuncs.contains(func)){
						fvo.setSelected(true);
					}
					fvs.add(fvo);
				}
			}
			mvo.setFvos(fvs);
			mvos.add(mvo);
		}
		
		return mvos;
	}

	public void saveFuncs(String roleId, List<String> menuIds, List<String> funcIds)
	{
		Role role = findById(roleId);
		List<Menu> menus = menuService.findByIds(menuIds);
		List<Function> funcs = funcService.findByIds(funcIds);
		
		role.setMenus(new HashSet<Menu>(menus));
		role.setFuncs(new HashSet<Function>(funcs));
	}

	public List<Role> findByIds(List<String> roleIds)
	{
		return (List<Role>) roleDao.findAll(roleIds);
	}
}
